package ru.mirent.json.entity;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import ru.mirent.json.ValidateJson;

import java.io.IOException;

/**
 * Обработка сериализованного Json, расположенного как значение родительского Json в экранированном виде.
 */
public class SerializeRawJson extends JsonSerializer<String> {
    @Override
    public void serialize(String s, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
        serializeStringAndAddToJsonValue(s, gen);
    }

    public void serializeWithType(String s, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
        serializeStringAndAddToJsonValue(s, gen);
    }

    /**
     * Сериализовать Json из экранированной строки и вывести его в форматированном виде с отступами в родительском Json.
     * @param s текст для преобразования
     * @param gen генератор Json для записи результата
     * @throws IOException исключение в случае ошибки
     */
    private void serializeStringAndAddToJsonValue(String s, JsonGenerator gen) throws IOException {
        ValidateJson validateJson = new ValidateJson(gen.getCodec());

        if (validateJson.apply(s)) {
            JsonNode jsonNode = deserializeJson(s, gen);
            gen.writeTree(jsonNode);
        } else {
            gen.writeString(s);
        }
    }

    /**
     * Десериализация Json.
     * @param s Json структуры в виде {@link String}
     * @return разложенный по элементам Json в виде структуры {@link JsonNode}
     * @throws IOException исключение в случае ошибки
     */
    private JsonNode deserializeJson(String s, JsonGenerator gen) throws IOException {
        JsonParser jsonParser = gen.getCodec().getFactory().createParser(s);
        return gen.getCodec().readTree(jsonParser);
    }
}
